﻿using AutoCommunication.Base;
using AutoCommunication.Enums;
using System;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;

#if NET5_0_OR_GREATER

#endif

namespace AutoCommunication.Helper
{
    /// <summary>
    /// 一些常用静态方法
    /// </summary>
    public static class Common
    {
        /// <summary>
        /// 转换布尔值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool GetBoolValue(this string value)
        {
            if (value == "1")
                return true;
            if (value == "0")
                return false;
            value = value.ToUpper();
            if (value == "TRUE")
                return true;
            if (value == "FALSE")
                return false;
            if (value == "ON")
                return true;
            return !(value == "OFF") && bool.Parse(value);
        }
        /// <summary>
        /// 根据<see cref="PropertyInfo"/> 数据类型转化返回值类型
        /// </summary>
        /// <param name="p"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object ObjToTypeValue(PropertyInfo p, string value)
        {
            object _value = null;
            if (p.PropertyType == typeof(bool))
                _value = value.GetBoolValue();
            else if (p.PropertyType == typeof(byte))
                _value = byte.Parse(value);
            else if (p.PropertyType == typeof(sbyte))
                _value = sbyte.Parse(value);
            else if (p.PropertyType == typeof(short))
                _value = short.Parse(value);
            else if (p.PropertyType == typeof(ushort))
                _value = ushort.Parse(value);
            else if (p.PropertyType == typeof(int))
                _value = int.Parse(value);
            else if (p.PropertyType == typeof(uint))
                _value = uint.Parse(value);
            else if (p.PropertyType == typeof(long))
                _value = long.Parse(value);
            else if (p.PropertyType == typeof(ulong))
                _value = ulong.Parse(value);
            else if (p.PropertyType == typeof(float))
                _value = float.Parse(value);
            else if (p.PropertyType == typeof(double))
                _value = double.Parse(value);
            else if (p.PropertyType == typeof(decimal))
                _value = decimal.Parse(value);
            else if (p.PropertyType == typeof(DateTime))
                _value = DateTime.Parse(value);
            else if (p.PropertyType == typeof(string))
                _value = value;
            else if (p.PropertyType == typeof(IPAddress))
                _value = IPAddress.Parse(value);
            else if (p.PropertyType.BaseType == typeof(Enum))
                _value = Enum.Parse(p.PropertyType, value);
            return _value;

        }
        /// <summary>
        /// 初始化串口的时候可能需要,用于直接读取数据,减少再次转化
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Encoding GetEncoding(EncodingEnum type)
        {
            //Todo 这里展示不不全,只是常用的,可以扩展为全部
            switch (type)
            {
                case EncodingEnum.UTF8:
                    return Encoding.UTF8;

                case EncodingEnum.Unicode:
                    return Encoding.Unicode;

                case EncodingEnum.BigEndianUnicode:
                    return Encoding.BigEndianUnicode;

                case EncodingEnum.ASCII:
                    return Encoding.ASCII;

                case EncodingEnum.Default:
                    return Encoding.Default;
            }
            return Encoding.UTF8;
        }

        /// <summary>
        /// 根据数据类型,获取他占用的字节个数
        /// </summary>
        /// <typeparam name="Tvariable"></typeparam>
        /// <param name="variable"></param>
        /// <returns></returns>
        /// <exception cref="System.Exception"></exception>
        public static int GetBytelength<Tvariable>(Tvariable variable) where Tvariable : BaseVariable
        {
            switch (variable.DataType)
            {
                case DataTypeEnum.None:
                    throw new System.Exception("未被定义的数据类型");
                case DataTypeEnum.Bool:
                    return 1;

                case DataTypeEnum.Byte:
                    return 1;

                case DataTypeEnum.Int16:
                    return 2;

                case DataTypeEnum.UInt16:
                    return 2;

                case DataTypeEnum.Int32:
                    return 4;

                case DataTypeEnum.UInt32:
                    return 4;

                case DataTypeEnum.Int64:
                    return 8;

                case DataTypeEnum.UInt64:
                    return 8;

                case DataTypeEnum.Float:
                    return 4;

                case DataTypeEnum.Double:
                    return 8;

                case DataTypeEnum.String:
                    return variable.Bytelength;

                case DataTypeEnum.Wstring:
                    return variable.Bytelength;

                case DataTypeEnum.Custom:
                    throw new System.Exception("数据类型未实现");
                default:
                    return 2;
            }
        }

        /// <summary>
        /// 根据存储区,返回不动的读取功能码,这里默认都是单个
        /// </summary>
        /// <param name="store"></param>
        /// <returns></returns>
        public static byte GetReadFunCode(ModbusStore store)
        {
            switch (store)
            {
                case ModbusStore.InCoil:
                    return 0X02;

                case ModbusStore.OutCoil:
                    return 0X01;

                case ModbusStore.InRegister:
                    return 0X04;

                case ModbusStore.HoldRegister:
                    return 0X03;

                default:
                    return 0X03;
            }
        }

        /// <summary>
        /// 根据存储区获得写入功能码
        /// </summary>
        /// <param name="store"></param>
        /// <param name="mutil"></param>
        /// <returns></returns>
        public static byte GetWriteFunCode(ModbusStore store, bool mutil = false)
        {
            if (mutil)//多个
            {
                switch (store)
                {
                    case ModbusStore.InCoil:
                        return 0X0F;

                    case ModbusStore.OutCoil:
                        return 0X0F;

                    case ModbusStore.InRegister:
                        return 0x10;

                    case ModbusStore.HoldRegister:
                        return 0X10;

                    default:
                        return 0X10;
                }
            }
            else
            {
                switch (store)
                {
                    case ModbusStore.InCoil:
                        return 0X05;

                    case ModbusStore.OutCoil:
                        return 0X05;

                    case ModbusStore.InRegister:
                        return 0x06;

                    case ModbusStore.HoldRegister:
                        return 0X06;

                    default:
                        return 0X06;
                }
            }
        }

        /// <summary>
        /// 数据解析
        /// </summary>
        /// <typeparam name="Tvariable"></typeparam>
        /// <param name="group"></param>
        /// <param name="Value"></param>
        /// <param name="Format"></param>
        /// <param name="DataChange"></param>
        /// <param name="Alarmer"></param>
        /// <returns></returns>
        public static Result<Group<Tvariable>> DataAnalysis<Tvariable>(Group<Tvariable> group, byte[] Value, EndianFormat Format, Action<BaseVariable> DataChange = null, Action<BaseVariable, AlarmEventArgs> Alarmer = null) where Tvariable : BaseVariable
        {
            Result<Group<Tvariable>> result = new Result<Group<Tvariable>>();
            result.Value = group;
            try
            {
                foreach (BaseVariable varable in group.Varablelist)
                {
                    switch (varable.DataType)
                    {
                        case DataTypeEnum.None:
                            result.IsSucceed = false; result.Err = "无效数据类型";
                            break;

                        case DataTypeEnum.Bool:
                            varable.Value = Value[(varable.StartByteAddress - group.StartByteAddress)].GetBit(varable.BitOffset);
                            break;

                        case DataTypeEnum.Byte:
                            varable.Value = Value[(varable.StartByteAddress - group.StartByteAddress)];//低字节
                            break;

                        case DataTypeEnum.Int16:
                            varable.Value = BitConverter.ToInt16(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.UInt16:
                            varable.Value = BitConverter.ToUInt16(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.Int32:
                            varable.Value = BitConverter.ToInt32(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.UInt32:
                            varable.Value = BitConverter.ToUInt32(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.Int64:
                            varable.Value = BitConverter.ToInt64(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.UInt64:
                            varable.Value = BitConverter.ToUInt64(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.Float:
                            varable.Value = (BitConverter.ToSingle(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0));
                            break;

                        case DataTypeEnum.Double:
                            varable.Value = BitConverter.ToDouble(Value.Skip((varable.StartByteAddress - group.StartByteAddress)).Take(varable.Bytelength).ToArray().Format(Format, true), 0);
                            break;

                        case DataTypeEnum.String:
                            //注意,只有在Winform中,才有中文编码,core和net5/6都会报错 https://docs.microsoft.com/zh-cn/dotnet/api/system.text.encoding?view=net-6.0
                            //第一个字节表示这个字符串被定义为多大
                            //第二个字节表示这个字符串实际写入了多少个字符
                            //所以,解析要跳过前两个
                            var length = Value[varable.StartByteAddress - group.StartByteAddress];
                            var lengthdata = Value[varable.StartByteAddress - group.StartByteAddress + 1];
                            //  varable.Value = Encoding.Default.GetString(Value.Skip((varable.StartByteAddress - group.StartByteAddress) + 2).Take(lengthdata).ToArray());
                            varable.Value = Encoding.GetEncoding("gb2312").GetString(Value.Skip((varable.StartByteAddress - group.StartByteAddress) + 2).Take(lengthdata).ToArray());
                            break;

                        case DataTypeEnum.Wstring:
                            //第1.2个字节表示这个字符串被定义为多大
                            //第3.4个字节表示这个字符串实际写入了多少个字符
                            //所以,解析要跳过前4个
                            var length2 = Value[varable.StartByteAddress - group.StartByteAddress];
                            var b1 = Value[varable.StartByteAddress - group.StartByteAddress + 2];
                            var b2 = Value[varable.StartByteAddress - group.StartByteAddress + 3];
                            var lengthdata2 = BitConverter.ToUInt16(new byte[] { b2, b1 }, 0) * 2;//一个字占用两个字节
                            varable.Value = Encoding.GetEncoding("gb2312").GetString(Value.Skip((varable.StartByteAddress - group.StartByteAddress) + 4).Take(lengthdata2).ToArray().Format(EndianFormat.BADC));
                            break;

                        case DataTypeEnum.Custom:
                            break;

                        default:
                            result.IsSucceed = false; result.Err = "无效数据类型";
                            break;
                    }

                    if (varable.Scale != 1 || varable.Offset != 0)
                    {
                        varable.Value = Convert.ToDouble(varable.Value) * varable.Scale + varable.Offset;
                    }
                    CheckIsAlarming(varable, DataChange, Alarmer);
                }
            }
            catch (Exception ex)
            {
                result.IsSucceed = false;
                result.Exception = ex;
            }

            return result;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="var"></param>
        /// <param name="DataChange"></param>
        /// <param name="Alarmer"></param>
        /// <returns></returns>
        public static Result CheckIsAlarming(BaseVariable var, Action<BaseVariable> DataChange = null, Action<BaseVariable, AlarmEventArgs> Alarmer = null)
        {
            Result result = new Result();
            try
            {
                if (var.DataChangeEnable && var.CacheValue?.ToString().Norm() != var.Value?.ToString().Norm())
                {
                    DataChange?.Invoke(var);
                    var.CacheValue = var.Value;
                }
                switch (var.DataType)
                {
                    case DataTypeEnum.Bool://为离散报警
                        if (var.AlarmType == AlarmType.RisingEdge)//上升沿报警
                        {
                            if (var.Value?.ToString() == "1" && var.RiseCacheValue == false)//报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = true,
                                    AlarmInfo = var.DiscreteAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = 1
                                });
                                var.FallCacheValue = var.Value.ToString() == "1";
                            }
                            if (var.Value?.ToString() == "0" && var.RiseCacheValue == true)//取消报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = false,
                                    AlarmInfo = var.DiscreteAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = 1
                                });
                                var.FallCacheValue = var.Value.ToString() == "1";
                            }
                        }
                        else//下降沿报警
                        {
                            if (var.Value?.ToString() == "0" && var.FallCacheValue == true)//报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = true,
                                    AlarmInfo = var.DiscreteAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = 0
                                });
                                var.FallCacheValue = var.Value.ToString() == "1";
                            }
                            if (var.Value?.ToString() == "1" && var.FallCacheValue == false)//取消报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = false,
                                    AlarmInfo = var.DiscreteAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = 0
                                });
                                var.FallCacheValue = var.Value.ToString() == "1";
                            }
                        }
                        break;

                    case DataTypeEnum.Byte:
                    case DataTypeEnum.Int16:
                    case DataTypeEnum.UInt16:
                    case DataTypeEnum.Int32:
                    case DataTypeEnum.UInt32:
                    case DataTypeEnum.Int64:
                    case DataTypeEnum.UInt64:
                    case DataTypeEnum.Float:
                    case DataTypeEnum.Double://为条件报警
                        float value = Convert.ToSingle(var.Value);
                        if (var.AlarmType.HasFlag(AlarmType.HAlarm))
                        {
                            if (value > var.HighAlarmSetValue && var.HighCacheValue < var.HighAlarmSetValue)//触发报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = true,
                                    AlarmInfo = var.HighAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.HighAlarmSetValue
                                });
                                var.HighCacheValue = value;
                            }
                            if (value < var.HighAlarmSetValue && var.HighCacheValue > var.HighAlarmSetValue)
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = false,
                                    AlarmInfo = var.HighAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.HighAlarmSetValue
                                });
                                var.HighCacheValue = value;
                            }
                        }
                        if (var.AlarmType.HasFlag(AlarmType.HHAlarm))
                        {
                            if (value > var.HHighAlarmSetValue && var.HHighCacheValue < var.HHighAlarmSetValue)//触发报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = true,
                                    AlarmInfo = var.HHighAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.HHighAlarmSetValue
                                });
                                var.HHighCacheValue = value;
                            }
                            if (value < var.HHighAlarmSetValue && var.HHighCacheValue > var.HHighAlarmSetValue)
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = false,
                                    AlarmInfo = var.HHighAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.HHighAlarmSetValue
                                });
                                var.HHighCacheValue = value;
                            }
                        }
                        if (var.AlarmType.HasFlag(AlarmType.LAlarm))
                        {
                            if (value < var.LowAlarmSetValue && var.LowCacheValue > var.LowAlarmSetValue)//触发报警 低报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = true,
                                    AlarmInfo = var.LowAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.LowAlarmSetValue
                                });
                                var.LowCacheValue = value;
                            }
                            if (value > var.LowAlarmSetValue && var.LowCacheValue < var.LowAlarmSetValue)
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = false,
                                    AlarmInfo = var.LowAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.LowAlarmSetValue
                                });
                                var.LowCacheValue = value;
                            }
                        }
                        if (var.AlarmType.HasFlag(AlarmType.LLAlarm))
                        {
                            if (value < var.LLowAlarmSetValue && var.LLowCacheValue > var.LLowAlarmSetValue)//触发报警 低报警
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = true,
                                    AlarmInfo = var.LLowAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.LLowAlarmSetValue
                                });
                                var.LLowCacheValue = value;
                            }
                            if (value > var.LLowAlarmSetValue && var.LLowCacheValue < var.LLowAlarmSetValue)
                            {
                                Alarmer?.Invoke(var, new AlarmEventArgs()
                                {
                                    IsTrigger = false,
                                    AlarmInfo = var.LLowAlarmNote,
                                    Value = var.Value.ToString(),
                                    SetValue = var.LLowAlarmSetValue
                                });
                                var.LLowCacheValue = value;
                            }
                            //  var.LLowCacheValue = value;
                        }
                        break;

                    default:
                        result.IsSucceed = false;
                        result.Err = "变量数据格式不正确";
                        break;
                }
            }
            catch (Exception ex)
            {
                result.IsSucceed = false;
                result.Exception = ex;
                throw;
            }

            return result;
        }
    }
}